package work.managercenter;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;

import utils.MyUtils;
import utils.Pair;

public class BauxiteShowVersionsRetriever {

	private static final String bauxiteTextUrl = "http://bauxitevm12.internetbrands.com:8080/dwr/exec/ShowVersionsForCategoryService.showVersions.dwr";
	private static final String bauxiteLoginCookieValue = "ibAutoLoginCookie=" +
			"gmarcone|DmfnS7zbfiZbJk4LmJJ5IwviJJ5" +
			"Ox3k30Qe4yUi1tVUoCbEOwCdiB8nV3nXA24aaEvl52dd02AHv6cPxUjeS6Z9fJAkFccSNgBaGbSw7LMAsZIuQpQZ9e5Gli5lIUdxg" +
			"pliSp1YwM7U6snSXptnQdXYWScIazwhZndKQa3Gl9yu912JjDDhcfWxXGcwG4lCS0KZYDthVR0oZEh6VDZRKpQV90NTqezG9YLKL" +
			"laNfV9vpSUZMSgniXhqBCN95q1m";

	private static final String inputFileLocation = "/home/gmarcone/bauxiteversions.txt";
	private static final String outputFileLocation = "/home/gmarcone/bauxiteversions.csv";
	private static final String separator = ",";

	// ID Version Stg By Prod By Date in Staging Date in Production
	private static final String[] columns = new String[] { "categoryId", "id", "dateCreated", "status", "promotedToStagingBy", "promotedToProductionBy", "dateInStaging", "dateInProduction", };

	public static void main(String[] args) {
		DefaultHttpClient httpclient = null;
		try {
			httpclient = new DefaultHttpClient();

			List<NameValuePair> basePostParams = new ArrayList<NameValuePair>();
			basePostParams.add(new BasicNameValuePair("callCount", "1"));
			basePostParams.add(new BasicNameValuePair("c0-scriptName", "ShowVersionsForCategoryService"));
			basePostParams.add(new BasicNameValuePair("c0-methodName", "showVersions"));
			basePostParams.add(new BasicNameValuePair("c0-id", "9764_1350487589656"));
			basePostParams.add(new BasicNameValuePair("xml", "true"));

			List<Pair<String, String>> bauxitecategories = parseBauxiteCategoriesFromFile(inputFileLocation);
			Writer fw = new FileWriter(outputFileLocation);

			printHeaders(fw);
			for (Pair<String, String> pair : bauxitecategories) {
				HttpPost httpost = new HttpPost(bauxiteTextUrl);
				httpost.setHeader("Cookie", bauxiteLoginCookieValue);

				List<NameValuePair> postParams = new ArrayList<NameValuePair>(basePostParams);
				postParams.add(new BasicNameValuePair("c0-param0", "number:" + pair.getFirst()));

				httpost.setEntity(new UrlEncodedFormEntity(postParams));
				HttpResponse response = httpclient.execute(httpost);

				List<Map<String, Object>> versiones = convert(response);

				print(pair,versiones, fw);
			}
			fw.flush();
			fw.close();
			httpclient.getConnectionManager().shutdown();

		} catch (Exception e) {
			e.printStackTrace(System.out);
		} finally {
			if (httpclient != null) {
				httpclient.getConnectionManager().shutdown();
			}
		}
	}

	private static void printHeaders(Writer fw) throws IOException {

		StringBuilder sb = new StringBuilder("Category Name").append(separator);

		for (String column : columns) {
			sb.append(column).append(separator);
		}
		sb.append(MyUtils.EOL);

		fw.write(sb.toString());
	}

	private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	private static void print(Pair<String, String> pair, List<Map<String, Object>> versiones, Writer fw) throws IOException {

		StringBuilder sb = new StringBuilder();

		for (Map<String, Object> map : versiones) {
			sb.append(pair.getSecond()).append(separator);
			for (String column : columns) {
				Object value = map.get(column);

				if (value == null || value.equals("null")) {

				} else if (value instanceof Date) {
					sb.append(dateFormat.format((Date) value));
				} else {
					sb.append(value);
				}
				sb.append(separator);
			}
			sb.append(MyUtils.EOL);
		}

		fw.write(sb.toString());
	}

	private static List<Map<String, Object>> convert(HttpResponse response) {
		try {
			String finalReturn = MyUtils.toString(response.getEntity().getContent(), null);
			finalReturn = finalReturn.substring(0, finalReturn.indexOf("DWREngine"));
			// System.out.println(finalReturn);
			return fromJStoJava(finalReturn);
		} catch (Exception e) {
			e.printStackTrace(System.out);
			return new ArrayList<Map<String, Object>>();
		}
	}

	@SuppressWarnings("unchecked")
	private static List<Map<String, Object>> fromJStoJava(String s) {
		Context cx = Context.enter();
		cx.setOptimizationLevel(-1);
		try {
			cx.setLanguageVersion(Context.VERSION_1_2);
			Scriptable scope = cx.initStandardObjects();

			cx.evaluateString(scope, s, "MySource", 1, null);

			Scriptable s0 = (Scriptable) scope.get("s0", scope);

			Object[] converted = (Object[]) convert(s0);
			List<Map<String, Object>> destino = new ArrayList<Map<String, Object>>(converted.length);
			for (int i = 0; i < converted.length; i++) {
				destino.add((Map) converted[i]);
			}

			return destino;
		} finally {
			Context.exit();
		}
	}

	@SuppressWarnings("unchecked")
	private static Object convert(Object origen) {
		if (origen == null) {
			return null;
		}

		String name = origen.getClass().getCanonicalName();

		if ("org.mozilla.javascript.NativeArray".equals(name)) {

			Object[] destino = (Object[]) Context.jsToJava(origen, (new Object[] {}).getClass());

			for (int i = 0; i < destino.length; i++) {
				destino[i] = convert(destino[i]);
			}

			return destino;

		} else if ("org.mozilla.javascript.NativeObject".equals(name)) {

			Map<String, Object> origen2 = (Map<String, Object>) origen;
			Map<String, Object> destino = new HashMap<String, Object>(origen2.size());

			for (String key : origen2.keySet()) {
				destino.put(key, convert(origen2.get(key)));
			}

			return destino;

		} else if ("org.mozilla.javascript.NativeDate".equals(name)) {

			Date destino = (Date) Context.jsToJava(origen, Date.class);

			return destino;

		} else if (origen instanceof Double) {
			Double d = (Double) origen;
			int i = (int) d.doubleValue();

			if (i == d.doubleValue()) {
				return Integer.valueOf(i);
			} else {
				return d;
			}
		} else {
			return origen;
		}
	}

	private static List<Pair<String, String>> parseBauxiteCategoriesFromFile(String fileLocation) throws IOException {
		String showVersions = "showVersions";

		String bauxiteCategoriesInput = MyUtils.readFileToString(new File(fileLocation));

		String iter = bauxiteCategoriesInput.substring(bauxiteCategoriesInput.indexOf(showVersions));

		List<Pair<String, String>> list = new ArrayList<Pair<String,String>>();

		while (iter.indexOf(showVersions) >= 0) {
			iter = iter.substring(iter.indexOf(showVersions));
			String functionCall = iter.substring(iter.indexOf(showVersions), iter.indexOf(")") + 1);

			String categoryName = functionCall.substring(functionCall.indexOf("'") + 1, functionCall.indexOf(",") - 1);
			String categoryId = functionCall.substring(functionCall.indexOf(",") + 1, functionCall.length() - 1);

			list.add(new Pair<String, String>(categoryId, categoryName));
			iter = iter.substring(iter.indexOf(")") + 1);
		}

		return list;
	}
}
